﻿
using System.Diagnostics;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using ST.Data;
using ST.ModelVM.ProtocolDefine;
using ST.ModelVM.ProtocolSimHost;
using ST.Simulator.Trans;

namespace ST.Simulator.Tasks
{
    public class TransTask : BackgroundService 
    {
        public static TransTask Instance;
        ILogger<TransTask> _logger;
        IDbContextFactory<AppDbContext> _fact;
        public List<ProtocolSimHostVM> lData;
        AppDbContext _DB;
        IRepository<ST.Data.ProtocolDefine> _IRepositoryProtocolDefine;
        IRepository<ST.Data.ProtocolSim> _IRepositoryProtocolSim;
        IRepository<ST.Data.ProtocolSimHost> _IRepositoryProtocolSimHost;
        IRepository<ST.Data.ProtocolSimLog> _IRepositoryProtocolSimLog;
        List<ProtocolSimLog> LstProtocolSimLog=new List<ProtocolSimLog>();
        public TransTask(ILogger<TransTask> logger 
              
            )
        {
            lData = new List<ProtocolSimHostVM>();
            _logger = logger;
            Instance = this;


        }
        ProtocolSJZDVM FindSJZD(ProtocolSimHostVM m, string key)
        {
            for (var i = 0; i < m.SJZD.Count; i++)
            {
                if (m.SJZD[i].Name == key)
                {
                    return m.SJZD[i];
                }
            }
            return null;
        }
        void CreatelData()
        {
           
            var lhost = _IRepositoryProtocolSimHost.GetAll().ToList();

            foreach(var mdb in lhost)
            {
                var m = ST.Core.Util.JSON.DeserializeObject<ProtocolSimHostVM>(mdb.Content);
                m.Id = mdb.Id;
                m.ProtocolSimId = mdb.ProtocolSimId;
                m.HostId = mdb.HostId;
                m.HostName = mdb.HostName;


                for (var i = 0; i < m.GDSJ.Count; i++)
                {
                    if (m.GDSJ[i].PropValue == null)
                    {
                        m.GDSJ[i].PropValue = new List<PropValue>();
                    }
                    if (m.GDSJ[i].PropValue.Count == 0)
                    {
                        for (var j = 0; j < m.GDSJ[i].Data.Count; j++)
                        {
                            var o = m.GDSJ[i].Data[j];
                            var mPropValue = new PropValue { };
                            m.GDSJ[i].PropValue.Add(mPropValue);
                            switch (o.PropType)
                            {
                                case "值":
                                case "精度":
                                case "上限":
                                case "下限":

                                    mPropValue.NumValue = 0;
                                    mPropValue.StrValue = mPropValue.NumValue.ToString();
                                    break;
                                default:
                                    var sjzd = FindSJZD(m, o.SJZDKey);
                                    if (sjzd != null)
                                    {
                                        if (sjzd.Data.Count > 0)
                                        {
                                            mPropValue.NumValue = sjzd.Data[0].IMin.HasValue ? sjzd.Data[0].IMin.Value : sjzd.Data[0].IMax.Value;
                                            mPropValue.StrValue = sjzd.Data[0].Name;
                                        }
                                    }
                                    break;

                            }
                        }
                    }

                    m.GDSJ[i].CreateBytes();
                }


                for (var i = 0; i < m.XHSJ.Count; i++)
                {
                    if (m.XHSJ[i].PropValue == null)
                    {
                        m.XHSJ[i].PropValue = new List<List<PropValue>>();
                    }
                    if (m.XHSJ[i].PropValue.Count == 0)
                    {
                        for (var j = 0; j < 10; j++)
                        {
                            var row = new List<PropValue>();
                            m.XHSJ[i].PropValue.Add(row);

                            for (var k = 0; k < m.XHSJ[i].Data.Count; k++)
                            {
                                var o = m.XHSJ[i].Data[k];
                                var mPropValue = new PropValue { };
                                row.Add(mPropValue);
                                switch (o.PropType)
                                {
                                    case "值":
                                    case "精度":
                                    case "上限":
                                    case "下限":

                                        mPropValue.NumValue = 0;
                                        mPropValue.StrValue = mPropValue.NumValue.ToString();
                                        break;
                                    default:
                                        var sjzd = FindSJZD(m, o.SJZDKey);
                                        if (sjzd != null)
                                        {
                                            if (sjzd.Data.Count > 0)
                                            {
                                                mPropValue.NumValue = sjzd.Data[0].IMin.HasValue ? sjzd.Data[0].IMin.Value : sjzd.Data[0].IMax.Value;
                                                mPropValue.StrValue = sjzd.Data[0].Name;
                                            }
                                        }
                                        break;

                                }
                            }
                        }

                    }
                    m.XHSJ[i].CreateBytes();
                }

                lData.Add(m);
            }
        }
        protected override async System.Threading.Tasks.Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _fact=ST.Core.Util.ServicesUtil.GetScopeRequiredService<IDbContextFactory<AppDbContext>>();
            _DB=_fact.CreateDbContext();
            _IRepositoryProtocolDefine = ST.Core.Util.ServicesUtil.GetScopeRequiredService<IRepository<ST.Data.ProtocolDefine>>();            
            _IRepositoryProtocolSim = ST.Core.Util.ServicesUtil.GetScopeRequiredService<IRepository<ST.Data.ProtocolSim>>();
            _IRepositoryProtocolSimHost = ST.Core.Util.ServicesUtil.GetScopeRequiredService<IRepository<ST.Data.ProtocolSimHost>>();
            _IRepositoryProtocolSimLog = ST.Core.Util.ServicesUtil.GetScopeRequiredService<IRepository<ST.Data.ProtocolSimLog>>();

          
            CreatelData();
            _logger.LogInformation("通讯主任务开始。。。。");
            while (!stoppingToken.IsCancellationRequested)
            {
                try {
               
                    await BatchSaveProtocolSimLog();
                    await  Task.Delay(5000,stoppingToken);
                }
                catch (Exception ex)
                {
                    
                }
            }
            await BatchSaveProtocolSimLog();
            _logger.LogInformation("通讯主任务结束");
        }
       async Task BatchSaveProtocolSimLog()
        {
            List<ProtocolSimLog> l = null;
            lock (LstProtocolSimLog)
            {
                l = new List<ProtocolSimLog>(LstProtocolSimLog);
                LstProtocolSimLog.Clear();
            }
            if (l.Count == 0)
            {
                return;
            }
            Stopwatch sw=Stopwatch.StartNew();
            _IRepositoryProtocolSimLog.DB.AddRange(l);
            await _IRepositoryProtocolSimLog.DB.SaveChangesAsync();
            _IRepositoryProtocolSimLog.DB.ChangeTracker.Clear();
            sw.Stop();
            _logger.LogInformation($"BatchSaveProtocolSimLog:数量{l.Count} 耗时：{sw.ElapsedMilliseconds}");

        }
        public void AddSimLog(Data.ProtocolSim sim,Int64 ProtocolSimHostId, string Lx, byte[] Data, string memo)
        {
            var m = new Data.ProtocolSimLog
            {
                Id = ST.Core.Util.IdUtil.NextId(),
                ProtocolSimHostId= ProtocolSimHostId,
                 ProtocolSimId= sim.Id,
                Lx = Lx,
                Data = ST.Core.Util.ByteUtil.ToHexString(Data),
                Memo = memo,
                Dt = DateTime.Now,
            };
            //_logger.LogInformation($"{m.Lx} :{m.Data}");
            lock (LstProtocolSimLog)
            {
                LstProtocolSimLog.Add(m);
            }
        }
        List<AbstractTrans> ltrans=new List<AbstractTrans>();
        public void StartSim(Int64 simid)
        {
            var t1 = ltrans.Where(a => a.Id == simid).FirstOrDefault();
            if (t1 != null)
            {
                return;
            }
            _IRepositoryProtocolSim.DB.ChangeTracker.Clear();
            var msim=_IRepositoryProtocolSim.GetById(simid);
            switch (msim.Mode)
            {
                case "TCP":
                    {
                        var t = ST.Core.Util.ServicesUtil.GetScopeRequiredService<TCPTrans>();
                        t.Start(msim);
                        ltrans.Add(t);
                    }
                    
                    break;
                case "UDP":
                    {
                        var t = ST.Core.Util.ServicesUtil.GetScopeRequiredService<UdpTrans>();
                        t.Start(msim);
                        ltrans.Add(t);
                    }

                    break;
                case "串口":
                    {
                        var t = ST.Core.Util.ServicesUtil.GetScopeRequiredService<PortTrans>();
                        t.Start(msim);
                        ltrans.Add(t);
                    }
                    break;
            }
        }
        public  void StopSim(Int64 simid)
        {
            var t=ltrans.Where(a => a.Id == simid).FirstOrDefault();
            if (t != null)
            {
                t.Stop();
                ltrans.Remove(t);
            }
        }
        public string GetRunState(Int64 simid)
        {
            var t = ltrans.Where(a => a.Id == simid).FirstOrDefault();
            if (t != null)
            {
                return "启动";
            }
            return "停止";
        }
    }

}
